package com.lv.common.ktx

import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.*
import android.graphics.drawable.Drawable
import android.media.MediaMetadataRetriever
import android.text.InputFilter
import android.text.Layout
import android.text.Spannable
import android.text.SpannableString
import android.text.Spanned
import android.text.StaticLayout
import android.text.style.ForegroundColorSpan
import android.text.style.ImageSpan
import android.text.style.StyleSpan
import android.text.style.UnderlineSpan
import android.view.LayoutInflater
import android.view.View
import android.view.animation.DecelerateInterpolator
import android.widget.EditText
import android.widget.ExpandableListView
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.ScrollView
import android.widget.TextView
import android.widget.ViewFlipper
import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.ViewCompat
import androidx.core.widget.NestedScrollView
import com.blankj.utilcode.util.CollectionUtils
import com.blankj.utilcode.util.GsonUtils
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.ScreenUtils
import com.blankj.utilcode.util.SizeUtils
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.imageview.ShapeableImageView
import com.google.gson.reflect.TypeToken
import com.lv.common.R
import com.lv.common.utils.Constants
import com.lv.common.utils.MyUtils
import com.lv.common.utils.YgxUtilsKt
import com.lv.common.widget.linkbar.ZFlowLayout
import com.lv.common.widget.textview.CenterImageSpan
import com.lv.common.widget.textview.GradientFontSpan
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.util.regex.Pattern
import kotlin.math.min

/**
 * 版权：Zhujiang 个人版权
 * @author zhujiang
 * 版本：1.5
 * 创建日期：2020/4/29
 * 描述：AndroidAOP
 *
 */


/**
 * textview 文字渐变色的扩展
 * 支持两种颜色
 */
fun TextView.setTextMoreColor(colors: IntArray) {
    // 定义渐变的起点和终点
    val positions = floatArrayOf(0f, 1f)
    // 定义LinearGradient，并指定渐变的起点和终点
    val linearGradient =
        LinearGradient(
            0f,
            0f,
            paint.textSize * text.length,
            0f,
            colors,
            positions,
            Shader.TileMode.CLAMP
        )
    // 设置TextView的渐变颜色
    this.paint.shader = linearGradient

}

/**
 * 文字前添加图片 图片和文字高一致
 */
fun TextView.setTextTag(
    drawable: Int,
    tagString: String = "",
    text: String = "",
    @ColorInt mStartColor: Int = Color.parseColor("#242424"),
) {
//    if (text == null || text.isEmpty()) {
//        return
//    }
    val mStartDrawable = resources.getDrawable(drawable, null)

    val textHeight = textSize.toInt()
    val aspectRatio = mStartDrawable.intrinsicWidth.toFloat() / mStartDrawable.intrinsicHeight
    val imageHeight = (textHeight * aspectRatio).toInt()
    // 计算图片宽度以适应文本高度
    val imageWidth = (imageHeight / aspectRatio).toInt()
    mStartDrawable.setBounds(0, 0, imageHeight, imageWidth) // 设置图片边界
    // 创建一个SpannableString对象
    val spannableString = SpannableString(tagString + text)
// 创建一个ImageSpan对象，参数分别是Context，图片资源，verticalAlignment
    val imageSpan =
        ImageSpan(mStartDrawable, ImageSpan.ALIGN_CENTER)
// 在SpannableString中前插入图片
    spannableString.setSpan(imageSpan, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
// 创建另一种颜色的ForegroundColorSpan
    val colorSpan = ForegroundColorSpan(mStartColor)

// 在SpannableString中插入颜色文字
    spannableString.setSpan(
        colorSpan,
        1,
        tagString.length ?: 1,
        Spannable.SPAN_INCLUSIVE_EXCLUSIVE
    )
    setText(spannableString)
}

/**
 * 字体扩展
 */
//fun TextView.setMyStyleTextView(content: String?) {
//    val typeface = Typeface.createFromAsset(
//        BaseApplication._context!!.assets,
//        "fonts/FZShangKJW.TTF"
//    )
//    this.typeface = typeface
//    this.text = content
//}
//添加下划线
fun String.underLine(): SpannableString {
    val spannableString = SpannableString(this)
    // 添加下划线（从第0个字符到文本末尾）
    spannableString.setSpan(
        UnderlineSpan(),  // 下划线样式
        0,                // 起始位置
        this.length,      // 结束位置
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
    )
    return spannableString
}

//判断是否包含
fun String.ContainsSelf(txt: String?): Boolean {
    return this.contains(txt ?: "") || (txt ?: "").contains(this)
}

//过滤换行
fun String.filterLine(): String {
    if (this.isEmpty()) {
        return ""
    }
    return this.replace("\n", "")
}

//过滤空格
fun String.filterSpace(): String {
    if (this.isEmpty()) {
        return ""
    }
    return this.replace("\n", "")
}

//小于0 转为0
fun String.zero(): String {
    if (this.isEmpty()) {
        return "0"
    }
    var zero = 0
    try {
        zero = this.toInt()
        if (zero < 0) {
            zero = 0
        }
    } catch (e: Exception) {
    }
    return "$zero"
}

fun String.isJson(): Boolean {
    if (this.isEmpty()) {
        return false
    }
    val pattern = Pattern.compile("^(\\{.*\\}|\\[.*\\])$")
    val matcher = pattern.matcher(this)
    return matcher.matches()
}

fun String.addressContains(name: String?): Boolean {
    if (this.isEmpty()) {
        return false
    }
    if (name.isNullOrEmpty()) {
        return false
    }
    if (this.contains(name) || name.contains(this)) {
        return true
    } else {
        return false
    }
}

fun String.isJsonTry(): Boolean {
    if (this.isEmpty()) {
        return false
    }
    try {
        JSONObject(this)
        return true
    } catch (e: JSONException) {
        try {
            JSONArray(this)
            return true
        } catch (e: JSONException) {
            return false
        }
    }
}

fun String.setBname(
    sub: String = "主营：",
    tvBname: TextView,
    tag: String = " | ",
    length: Int = 0
) {
    val isJson = this.isJson()
    if (isJson) {
        try {
            val jsonType = object : TypeToken<List<String>>() {}.type
            var bnams: List<String> = GsonUtils.fromJson(this, jsonType)
            var size = length
            if (length > bnams.size) {
                size = bnams.size
            }
            if (length != 0) {
                bnams = bnams.subList(0, size)
            }
            if (CollectionUtils.isNotEmpty(bnams)) {
                var bnameString = ""
                bnams.forEach { item ->
                    bnameString = "${bnameString}${tag}${item}"
                }
                if (bnameString.isNotEmpty() && bnameString.startsWith(tag)) {
                    bnameString = bnameString.drop(tag.length)
                }
                tvBname.text = "$sub$bnameString"
            } else {
                tvBname.text = ""
            }
        } catch (e: Exception) {
            tvBname.text = ""
        }
    } else {
        tvBname.text = sub + this.replace(",", tag)
    }
}

/**
 * 是否超出 maxlines 显出maxlines的总字数
 */
fun TextView.isTextOverflowing(maxLines: Int): Pair<Boolean, Int> {
    val layout = layout
    var totalChars = 0
    for (i in 0 until min(lineCount, maxLines)) {
        totalChars += layout.getLineEnd(i) - layout.getLineStart(i)
    }
    val over = layout != null && lineCount > maxLines
    return Pair(over, totalChars)
}

//文字前面拼图片 图片居中
fun TextView.displaySpannableSuperWith2Pic(
    drawable: Int, textString: String?, drawable2: Int = -1
) {
    val image = CenterImageSpan(context, drawable)
    var image2: CenterImageSpan? = null
    if (drawable2 != -1) {
        image2 = CenterImageSpan(context, drawable2)
    }

    // 在文字前插入图片，并设置间距
    var startIndex = 0
    var spacing = "    " // 文字前间距（空格字符）
    if (drawable2 == -1) {
        spacing = "  "
    }
    val spacingImage = " " // 图片间距（空格字符）
    val spannableString = SpannableString("$spacing$textString")
// 在文字前添加第一个图片
    spannableString.setSpan(image, startIndex, startIndex + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
    startIndex += 1
    // 插入间距
    spannableString.setSpan(
        spacingImage,
        startIndex,
        spacingImage.length + startIndex,
        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
    )
    startIndex += spacingImage.length
    // 在文字前添加第二个图片
    if (image2 != null) {
        spannableString.setSpan(
            image2,
            startIndex,
            startIndex + 1,
            Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
        )
    }

    // 设置 TextView 的文本
    this.text = spannableString
}

/**
 * string 转 SpannableString
 */
fun String.setTextSpan(typeface: Int = Typeface.NORMAL): SpannableString {
    val spannedString = SpannableString(this)
    val styleSpan = StyleSpan(typeface)
    spannedString.setSpan(
        styleSpan,
        0,
        this.length,
        Spanned.SPAN_INCLUSIVE_INCLUSIVE
    )
    return spannedString
}

//price 去小数点后面的无效0
fun String.priceSmallDot(tag: String = ""): String {
    var myPrice = this
    if (myPrice.endsWith(".0") || myPrice.endsWith(".00")) {
        myPrice = myPrice.split(".")[0]

    } else if (myPrice.contains(".") && myPrice.endsWith("0")) {
        myPrice = myPrice.substring(0, myPrice.length - 1)
    }
    return tag + myPrice
}

/**
 * string 根据指定字符串分割 去重
 */
fun String.setSplite(chat: String, newChat: String): String {
    var show = ""
    val split = split(chat)
    split.forEach { it ->
        if (it.isNotEmpty() && !show.contains(it)) {
            show += "$newChat${it}"
        }
    }
    if (newChat.isNotEmpty() && show.startsWith(newChat)) {
        show = show.drop(newChat.length)
    }
    return show
}

/**
 * 图片链接后面拼边框
 * @param water 边框链接
 * @param zipW 显示的宽高 单位 px
 * @param q  显示的图片质量
 */
fun String.urlAddBorder(
    water: String?,
    zipW: Int = ScreenUtils.getScreenWidth(),
    q: Int = 100
): String {
    if (water.isNullOrEmpty()) {
        return MyUtils.makeSmallerImg(this, zipW, q)
    }
    val (imgW, imgH, k) = YgxUtilsKt.getImageWH(this, zipW, false)
    val imageName = water.replace(Constants.ALIHEADER, "")
    var imageW = imgW.toInt()
    var imageH = imgH.toInt()
    if (zipW != 0) {
        imageW = zipW
        imageH = ((zipW * imgH) / imgW).toInt()
    }
    val preparStr = "?x-oss-process=image/resize,w_$imageW,h_$imageH,m_fixed,limit_0"
    val base64String = YgxUtilsKt.encodeToBase64("$imageName$preparStr")
    var qual = ""
    //设置图片质量的代码
//    if (q != 0) {
//        qual = "/quality,q_$q"
//    }
    val constStr =
        "?x-oss-process=image/resize,w_$imageW,h_$imageH,m_fixed,limit_0/format,jpg/watermark,image_"
    val otherStr = ",g_nw,x_0,y_0$qual"
    return this + constStr + base64String + otherStr
}

fun TextView.setColors(text: String?, mStartColor: Int, mEndColor: Int) {
    if (text == null || text.isEmpty()) {
        return
    }

    var textString = text
    val with = SizeUtils.dp2px(315.0f)
    val staticLayout = StaticLayout(
        text, paint, with, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false
    )
    val lineEnd = staticLayout.getLineEnd(0)
    val textLength = textString.length
    if (textLength > lineEnd) {
        textString = text.substring(0, lineEnd - 1) + "…"
    }
    val spannableString = SpannableString(textString)
    val gradientFontSpan = GradientFontSpan(mStartColor, mEndColor)

    spannableString.setSpan(
        gradientFontSpan, 0, textString.length,
        Spanned.SPAN_INCLUSIVE_INCLUSIVE
    )
    setText(spannableString)
    invalidate()
}

fun ExpandableListView.collapseGroupWithAnimation(
    groupPosition: Int
) {
    // 获取展开状态的组项视图
    val groupView = getChildAt(groupPosition)

    // 属性动画：Y轴缩放动画效果从1变为0
    val animator: ObjectAnimator = ObjectAnimator.ofFloat(groupView, "scaleY", 1f, 0f)
    animator.duration = 200 // 设置动画时长为200ms
    animator.start()
    collapseGroup(groupPosition) // 调用collapseGroup()方法将组项收起
}

fun ExpandableListView.expandGroupWithAnimation(
    groupPosition: Int
) {
    // 获取收起状态的组项视图
    val groupView = getChildAt(groupPosition)

    // 属性动画：Y轴缩放动画效果从0变为1
    val animator: ObjectAnimator = ObjectAnimator.ofFloat(groupView, "scaleY", 0f, 1f)
    animator.duration = 200 // 设置动画时长为200ms
    animator.start()
    expandGroup(groupPosition) // 调用expandGroup()方法将组项展开
}

/**
 * 旋转
 * @param value 角度
 * @param isAnimate 动画
 */
fun View.rotation(value: Float, isAnimate: Boolean) {
    if (isAnimate) {
        ViewCompat.animate(this).setDuration(200)
            .setInterpolator(DecelerateInterpolator())
            .rotation(value)
            .start()
    } else {
        this.rotation = value
    }
}

/**
 * 设置tag标签
 */
fun ZFlowLayout.setDatas(list: List<String>?) {
    val mViewList = mutableListOf<View>()
    if (!list.isNullOrEmpty()) {
        list.forEach { item ->
            val textChild = LayoutInflater.from(context)
                .inflate(
                    com.lv.common.R.layout.text_tag_layout,
                    this, false
                ) as TextView
            val texts = item.split("-")
            if (!texts.isNullOrEmpty() && texts.size > 1) {
                val text = texts[1]
                textChild.text = text
                mViewList.add(textChild)
            }
        }
        setChildren(mViewList)
    }

}

/**
 * @param mDiskCacheStrategy true 不缓存数据
 */
fun ImageView.LoadSrc(url: String?, urlError: String = "", mDiskCacheStrategy: Boolean = false) {
    if (mDiskCacheStrategy) {
        val options = RequestOptions()
            .diskCacheStrategy(DiskCacheStrategy.NONE)
            .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
            .format(DecodeFormat.PREFER_RGB_565)
        Glide.with(context).load(url).apply(options)
            .error(urlError.ifEmpty { R.drawable.icon_logo_gray }).into(this)
    } else {
        Glide.with(context).load(url).error(urlError.ifEmpty { R.drawable.icon_logo_gray })
            .into(this)

    }
}

/**
 * @param mDiskCacheStrategy true 不缓存数据
 * frame(1000000) 表示加载视频的第 1 秒（1000000 微秒）的帧作为缩略图。
 */
fun ImageView.LoadAsBitmapByVideoUrl(
    url: String?,
    urlError: String = "",
    mDiskCacheStrategy: Boolean = false
) {
    if (mDiskCacheStrategy) {
        if (!url.isNullOrEmpty() && url.endsWith(".mp4")) {
            val options = RequestOptions().frame(1000000)
            Glide.with(context).asBitmap().load(url).apply(options)
                .error(urlError.ifEmpty { R.drawable.icon_logo_gray }).into(this)
        } else {
            Glide.with(context).asBitmap().load(url)
                .error(urlError.ifEmpty { R.drawable.icon_logo_gray }).into(this)
        }
    } else {
        Glide.with(context).asBitmap().load(url)
            .error(urlError.ifEmpty { R.drawable.icon_logo_gray }).into(this)
    }
}

fun ImageView.LoadSrc(url: Bitmap?, urlError: String = "") {
    Glide.with(context).load(url).error(urlError.ifEmpty { R.drawable.icon_logo_gray }).into(this)
}

fun ImageView.LoadSrc(url: Int?, urlError: String = "") {
    Glide.with(context).load(url).error(urlError.ifEmpty { R.drawable.icon_logo_gray }).into(this)
}

fun ImageView.LoadSrc(url: Int?, urlError: Bitmap?) {
    Glide.with(context).load(url).error(urlError).into(this)
}

fun ImageView.LoadSrcint(url: String?, @DrawableRes downIconResId: Int) {
    Glide.with(context).load(url).error(downIconResId).into(this)
}

fun View.ToBitmap(color: Int = Color.TRANSPARENT): Bitmap {
    // 创建一个和给定View相同大小的Bitmap
    val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
    // 使用Canvas来将View的内容绘制到Bitmap上
    val canvas = Canvas(bitmap)
    // 设置背景为透明
    canvas.drawColor(color)
    layout(0, 0, width, height)
    // 将View绘制在Canvas上
    draw(canvas)
    // 遍历Bitmap的每个像素，检查颜色是否为黑色，如果是，则将其颜色改为透明
//    val paint = Paint()
//    val rect = Rect(0, 0, bitmap.width, bitmap.height)
//    paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
//    canvas.drawRect(rect, paint)
    return bitmap
}

// 在需要改变长度的时候调用这个函数
fun EditText.setMaxLength(maxLength: Int) {
    filters[0] = InputFilter.LengthFilter(maxLength)
    this.filters = filters
}

fun View.limitTranslationX(translationX: Float, screenWidth: Int) {
    val minTranslationX = -this.width.toFloat() // 最小限制，使得View的左侧边缘停留在屏幕左边缘
    val maxTranslationX = screenWidth.toFloat() // 最大限制，使得View的右侧边缘停留在屏幕右边缘

    this.translationX = translationX.coerceIn(minTranslationX, maxTranslationX)
}

//滤色
fun ConstraintLayout.applyGrayScale() {
    for (i in 0 until childCount) {
        val view = getChildAt(i)
        val colorMatrix = ColorMatrix().apply {
            setSaturation(0f) // 设置饱和度为0实现灰度效果
        }
        if (view is ShapeableImageView) {
            view.colorFilter = ColorMatrixColorFilter(colorMatrix)
        } else {
            val paint = Paint().apply {
                colorFilter = ColorMatrixColorFilter(colorMatrix)
            }
            view.setLayerType(View.LAYER_TYPE_HARDWARE, paint)
        }
    }
}

//滤色
fun View.applyGrayScale(filter: Boolean = true) {
    if (filter) {
        val colorMatrix = ColorMatrix().apply {
            setSaturation(0f) // 设置饱和度为0实现灰度效果
        }
        if (this is ShapeableImageView) {
            this.colorFilter = ColorMatrixColorFilter(colorMatrix)
        } else {
            val paint = Paint().apply {
                colorFilter = ColorMatrixColorFilter(colorMatrix)
            }
            this.setLayerType(View.LAYER_TYPE_HARDWARE, paint)
        }
    } else {
        val colorMatrix = ColorMatrix().apply {
            setSaturation(1f) // 设置饱和度为0实现灰度效果
        }
        if (this is ShapeableImageView) {
            this.colorFilter = null
        } else {
            val paint = Paint().apply {
                colorFilter = ColorMatrixColorFilter(colorMatrix)
            }
            this.setLayerType(View.LAYER_TYPE_HARDWARE, paint)
        }
    }

}


//重复点击事件处理
inline fun View.setSafeListener(crossinline action: () -> Unit) {
    var lastClick = 0L
    setOnClickListener {
        val gap = System.currentTimeMillis() - lastClick
        lastClick = System.currentTimeMillis()
        if (gap < 1500) return@setOnClickListener
        action.invoke()
    }
}

fun View.OnClickListener.initSingleClickListener(vararg views: View?) {
    views.map {
        it?.setOnSingleClickListener(this)
    }
}

fun View.setOnSingleClickListener(listener: View.OnClickListener) {
    setOnClickListener {
        isClickable = false
        listener.onClick(this)
        postDelayed({ isClickable = true }, 1000)
    }
}


/**
 * 设置轮播
 * @param titles 数据源
 * @param times 播放间隔
 */
fun <T> ViewFlipper.setViewFlipper(
    context: Context,
    titles: List<T>,
    times: Int,
    mLayout: (i: Int) -> View,
) {
    removeAllViews()
    //获取ViewFlipper控件id
    for (i in titles.indices) {
        val invoke = mLayout.invoke(i)
        //动态添加视图
        addView(invoke)
    }
    //设置的时间间隔来开始切换所有的View,切换会循环进行
    if (titles.size > 1) {
        startFlipping()
        //视图进入动画
        setInAnimation(context, com.lv.common.R.anim.home_notice_in)
        //视图退出动画
        setOutAnimation(context, com.lv.common.R.anim.home_notice_out)
        //自动开始滚动
        isAutoStart = true
        //视图的切换间隔
        flipInterval = times
    }

}

// 扩展函数：读取文件为字节数组
fun String.readFileToByteArray(): ByteArray? {
    val file = File(this)
    if (!file.exists()) {
        LogUtils.e("FileUtils", "文件不存在: $this")
        return null
    }

    return try {
        FileInputStream(file).use { fis ->
            ByteArrayOutputStream().use { bos ->
                val buffer = ByteArray(1024)
                var bytesRead: Int
                while (fis.read(buffer).also { bytesRead = it } != -1) {
                    bos.write(buffer, 0, bytesRead)
                }
                bos.toByteArray()
            }
        }
    } catch (e: IOException) {
        LogUtils.e("FileUtils", "读取文件失败: ${e.message}")
        null
    }
}

// 扩展函数：获取视频尺寸
fun String.getVideoDimensions(): Pair<Int, Int> {
    val dimensions = Pair(-1, -1) // {width, height}
    MediaMetadataRetriever().use { retriever ->
        try {
            retriever.setDataSource(this)
            val width =
                retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toInt()
            val height =
                retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toInt()
            if (width != null && height != null) {
                return Pair(width, height)
            }
        } catch (e: Exception) {
            LogUtils.e("VideoUtils", "获取视频尺寸失败: ${e.message}")
        }
    }
    return dimensions
}

fun AppBarLayout.setupAppBarLayoutListener(onStateChange: (AppBarState) -> Unit) {
    var currentState = AppBarState.EXPANDED
    this.addOnOffsetChangedListener(
        AppBarLayout.OnOffsetChangedListener { _, verticalOffset ->
            val totalScrollRange = this.totalScrollRange
            val isExpanded = verticalOffset == 0
            val isCollapsed = Math.abs(verticalOffset) >= totalScrollRange
            val newState = when {
                isExpanded -> AppBarState.EXPANDED
                isCollapsed -> AppBarState.COLLAPSED
                else -> AppBarState.PARTIALLY_COLLAPSED
            }

            if (newState != currentState) {
                currentState = newState
                onStateChange(newState)
            }
        }
    )
}

// 动画切换为竖向
fun LinearLayout.animateTabToVertical() {
    this.orientation = LinearLayout.VERTICAL
    // 可添加动画：平移、缩放、透明度
    this.animate()
        .alpha(1f)
        .setDuration(300)
        .start()
}

// 动画切换为横向
fun LinearLayout.animateTabToHorizontal() {
    this.orientation = LinearLayout.HORIZONTAL
    this.animate()
        .alpha(1f)
        .setDuration(300)
        .start()
}

// 定义折叠状态枚举
enum class AppBarState {
    EXPANDED,       // 完全展开
    COLLAPSED,      // 完全折叠
    PARTIALLY_COLLAPSED // 部分折叠（中间状态）
}





